﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Controls;
using MyFloridaHouse.libSvOpenDistricts.DataService;
using MyFloridaHouse.ServiceConn.DistrBldrSvcRef;
using MyFloridaHouse.libSvOpenDistricts.Districts;

namespace MyFloridaHouse.libSvMassDataReport.Reports
{
           
    public partial class ACSDistrictSummary : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        #region properties

        private string _planName = "";
        public string planName
        {
            get { return _planName; }
            set
            {
                if (_planName != value)
                {
                    _planName = value;
                    NotifyPropertyChanged("planName");
                }
            }
        }

        private int _planDistrictCount;
        public int planDistrictCount
        {
            get { return _planDistrictCount; }
            set
            {
                if (_planDistrictCount != value)
                {
                    _planDistrictCount = value;
                    NotifyPropertyChanged("planDistrictCount");
                }
            }
        }

        private string _planType = "";
        public string planType
        {
            get { return _planType; }
            set
            {
                if (_planType != value)
                {
                    _planType = value;
                    NotifyPropertyChanged("planType");
                }
            }
        }

        private string _planLastUpdateTimeStamp = "";
        public string planLastUpdateTimeStamp
        {
            get { return _planLastUpdateTimeStamp; }
            set
            {
                if (_planLastUpdateTimeStamp != value)
                {
                    _planLastUpdateTimeStamp = value;
                    NotifyPropertyChanged("planLastUpdateTimeStamp");
                }
            }
        }

        public string selectedTableIDList 
        { 
            get 
            {
                List<string> resultList = new List<string>();
                foreach (var subject in ACSSubjectTree)
                {
                    List<string> tmpList = (from item in subject.subList
                                        where (item.isSelected)
                                        select item.tblID).ToList();
                    resultList.AddRange(tmpList);
                }
                return  string.Join( ",",resultList); 
            } 
        }


        private bool _isACSDefinitionLoadComplete = false;
        public bool isACSDefinitionLoadComplete
        {
            get { return _isACSDefinitionLoadComplete; }
            set
            {
                if (_isACSDefinitionLoadComplete != value)
                {
                    _isACSDefinitionLoadComplete = value;
                    NotifyPropertyChanged("isACSDefinitionLoadComplete");
                }
            }
        }

        private ObservableCollection<string> _districtList = new ObservableCollection<string>();
        public ObservableCollection<string> districtList
        {
            get { return _districtList; }
            set
            {
                if (_districtList != value)
                {
                    _districtList = value;
                    NotifyPropertyChanged("districtList");
                }
            }
        }

        private List<string> districtCondensedList = new List<string>();

        private int _districtSelectedIndex = -1;
        public int districtSelectedIndex
        {
            get { return _districtSelectedIndex; }
            set
            {
                if (_districtSelectedIndex != value)
                {
                    _districtSelectedIndex = value;
                    NotifyPropertyChanged("districtSelectedIndex");
                }
            }
        }

        private ObservableCollection<ACSDistrictSummaryListItem> _ACSSubjectTree = new ObservableCollection<ACSDistrictSummaryListItem>();
        public ObservableCollection<ACSDistrictSummaryListItem> ACSSubjectTree
        {
            get { return _ACSSubjectTree; }
            set
            {
                if (_ACSSubjectTree != value)
                {
                    _ACSSubjectTree = value;
                    NotifyPropertyChanged("ACSSubjectTree");
                }
            }
        }


        private ObservableCollection<ACSDistrictSummarySection> _ACSDistrictSummaryReportSections = new ObservableCollection<ACSDistrictSummarySection>();
        public ObservableCollection<ACSDistrictSummarySection> ACSDistrictSummaryReportSections
        {
            get { return _ACSDistrictSummaryReportSections; }
            set
            {
                if (_ACSDistrictSummaryReportSections != value)
                {
                    _ACSDistrictSummaryReportSections = value;
                    NotifyPropertyChanged("ACSDistrictSummaryReportSections");
                }
            }
        }


        #endregion

        //set up an interface to our data services
        private ServiceDAL _serviceDAL;
        public ServiceDAL serviceDAL
        {
            get { return _serviceDAL; }
            set
            {
                if (_serviceDAL != value)
                {
                    _serviceDAL = value;
                    NotifyPropertyChanged("serviceDAL");
                }
            }
        }

        //public FileOpen fileOpen{get; set;}
        private DistrictPlanTypes districtPlanTypes;

        private Dictionary<int, ACSDistrictSummaryReportDefinitionDTO> acsDictionary = new Dictionary<int, ACSDistrictSummaryReportDefinitionDTO>();
        private Dictionary<int, ACSDistrictSummaryDataDTO> acsDataQueryResults = new Dictionary<int,ACSDistrictSummaryDataDTO>();


        public ACSDistrictSummary(Uri appCurrentHostSource, StackPanel childWindowStackPanel)
        {
			//Todo: Refactor all occurrances of: serviceDAL = new ServiceDAL(appCurrentHostSource); appCurrentHostSource is no longer needed.
			//serviceDAL = new ServiceDAL(appCurrentHostSource);
			serviceDAL = new ServiceDAL();


            //fileOpen = new FileOpen(serviceDAL, childWindowStackPanel);
            //fileOpen.PropertyChanged += new PropertyChangedEventHandler(MemberPropertyChanged);
            //FileOpen.FileOpenComplete += OnOpenDistrictPlanFileComplete;


            IntializeCommands();

            // initialize structures with data stored in dal
            districtPlanTypes = new DistrictPlanTypes(serviceDAL);

            GetACSReportDefinition();

        }

        public void LoadACSDistrictSummaryReportDefintion(ObservableCollection<ACSDistrictSummaryReportDefinitionDTO> definitionRows)
        {
            foreach (var def in definitionRows)
            {
                acsDictionary.Add(def.dictionaryID, def);
            }

            BuildReportSelectorList();
            isACSDefinitionLoadComplete = true;
        }

        //public void StartFileOpen()
        //{
        //    //fileOpen.Begin();
        //}

        //public void OnOpenDistrictPlanFileComplete(object sender, FileOpenCompleteEventArgs args)
        //{
        //    try
        //    {
        //        districtPlanXML = DistrictPlan.FromXML(args.fileData);
        //    }
        //    catch ( Exception ex)
        //    {
        //        Log.HandleInternalError("Unable to load district plan: " + ex.Message);
        //    }

        //    if (districtPlanXML == null)
        //    {
        //        MessageBox.Show("Sorry, the load XML file failed.  Hint: you have to load an XML file for the ACS report. ");
        //        return;
        //    }

        //    // need to add a blank entry for the unassigned list.  We don't store it in the xml file.
        //    districtCondensedList.Clear();
        //    districtCondensedList.Add("");
        //    for (int ndx = 0; ndx < districtPlanXML.numberOfDistricts; ndx++)
        //    {
        //        districtCondensedList.Add(districtPlanXML.districtList[ndx].condensedRegionList);
        //    }

        //    planName = districtPlanXML.planName;
        //    if (planName.Length == 0)
        //    {
        //        planName = "Unspecified";
        //    }
        //    planType = districtPlanXML.planType;
        //    planDistrictCount = districtPlanXML.numberOfDistricts;
        //    districtList.Clear();
        //    //need to add the unassigned district
        //    districtList.Add("Select a District");
        //    for (int i = 1; i <= planDistrictCount; i++)
        //    {
        //        districtList.Add(i.ToString());
        //    }
        //    districtSelectedIndex = 0;
        //    if (planDistrictCount > 1)
        //    {
        //        districtSelectedIndex = 1;
        //    }
        //    MessageBox.Show("Loaded district plan with [" + planDistrictCount.ToString() + "] districts");

        //}

        private bool checkAllTables = true;
        public void CheckAllTables()
        {
            foreach (var table in ACSSubjectTree)
            {
                table.isSelected = checkAllTables;
            }
            checkAllTables = !checkAllTables;
        }


        private void BuildReportSelectorList()
        {
            var titleQuery = from item in acsDictionary
                             where item.Value.header.Contains("_000A")
                             select item;

            string subject_area = "not specified yet";
            ObservableCollection<ACSDistrictSummaryListItem> childList = null;

            // we don't need recursion here, because we're only trying to go two levels deep
            foreach (var titleRow in titleQuery)
            {
                if (titleRow.Value.subject_area != subject_area)
                {
                    subject_area = titleRow.Value.subject_area;
                    childList = AddACSTableTreeItem(ACSSubjectTree, titleRow.Value.subject_area, titleRow.Value.detailDesc, titleRow.Value.tableID, titleRow.Value.dictionaryID);
                    AddACSTableTreeItem(childList, titleRow.Value.detailDesc, "", titleRow.Value.tableID, titleRow.Value.dictionaryID);
                }
                else
                {
                    if (childList != null)
                    {
                        AddACSTableTreeItem(childList, titleRow.Value.detailDesc, "", titleRow.Value.tableID, titleRow.Value.dictionaryID);
                    }
                    else
                    {
                        throw new SystemException("ACSDistrictSummary report, attempted to add item to undefined selector child list");
                    }
                }
            }

            foreach (var subject in ACSSubjectTree)
            {
                foreach (var section in subject.subList)
                {
                    var universeQuery = from item in acsDictionary
                                        where (item.Value.header.Contains("_000B")) & (item.Value.tableID == section.tblID)
                                        select item;
                    foreach (var universe in universeQuery)
                    {
                        section.subName = universe.Value.detailDesc;
                    }
                }
            }
            


        }

        private ObservableCollection<ACSDistrictSummaryListItem> AddACSTableTreeItem(ObservableCollection<ACSDistrictSummaryListItem> subjectList, string name, string subName, string tblID, int dictionaryID)
        {
            ACSDistrictSummaryListItem newItem = new ACSDistrictSummaryListItem();
            newItem.name = name;
            newItem.subName = subName;
            newItem.dictionaryID = dictionaryID;
            newItem.tblID = tblID;
            newItem.subList = new ObservableCollection<ACSDistrictSummaryListItem>();

            subjectList.Add(newItem);

            return newItem.subList;
        }


        public void LoadACSDistrictSummaryData(ObservableCollection<ACSDistrictSummaryDataDTO> dataRows)
        {
            const int MaxStringIndent = 30;
            List<string> indentArray = new List<string>();
            string indentString = "";

            for (int i = 0; i < MaxStringIndent; i++)
            {
                indentArray.Add(indentString);
                indentString += " ";
            }

            _ACSDistrictSummaryReportSections.Clear();
            foreach(var tbl in ACSSubjectTree)
            {
                if (tbl != null)
                {
                    foreach (var subTbl in tbl.subList)
                    {
                        if (subTbl.isSelected)
                        {
                            ACSDistrictSummarySection newSection = new ACSDistrictSummarySection();
                            newSection.sectionHeading = "FLORIDA ACS DATA " + planType + " DISTRICT " + districtSelectedIndex;
                            newSection.sectionTitle = tbl.name;
                            newSection.sectionSubTitle = subTbl.name;
                            newSection.sectionUniverse = subTbl.subName;
                            newSection.dataList = new List<ACSDistrictSummaryReportRow>();

                            // get all dictionary items and their data values for this table
                            var dataDictionary = (from dat in dataRows 
                                            join dict in acsDictionary
                                            on dat.dictionaryID equals dict.Key 
                                            where dict.Value.tableID == subTbl.tblID
                                            select new {dict, dat }).ToDictionary(k => k.dict.Key);

                            
                            foreach (var completeData in dataDictionary)
                            {
                                float itemValueAsNumber = 0;
                                float parentValueAsNumber = 0;
                                string itemValuePercent = "100%";

                                string itemValue = completeData.Value.dat.dataValue;
                                int parentID = completeData.Value.dict.Value.parentDictionaryID;

                                if (parentID >= 0)
                                {
                                    var parentItemValue = (from k in dataDictionary where k.Key == parentID select k).First().Value.dat.dataValue;
                                    bool isItemValueANumber = float.TryParse(itemValue, out itemValueAsNumber);
                                    bool isParentValueANumber = float.TryParse(parentItemValue, out parentValueAsNumber);
                                    if (isItemValueANumber & isParentValueANumber)
                                    {
                                        itemValuePercent = string.Format("{0:0%}",((itemValueAsNumber / parentValueAsNumber))) ;

                                    }
                                    else
                                    {
                                        itemValuePercent = "Error";
                                    }
                                }

                                int level = completeData.Value.dict.Value.level;
                                if (level < 0) level = 0;
                                if (level > MaxStringIndent) level = MaxStringIndent;
                                indentString = indentArray[level];

                                ACSDistrictSummaryReportRow newDataRow = new ACSDistrictSummaryReportRow();
                                newDataRow.header = completeData.Value.dict.Value.header;
                                newDataRow.dictionaryID = completeData.Value.dict.Value.dictionaryID;
                                if (completeData.Value.dict.Value.parentDictionaryID == -1)
                                {
                                    //newDataRow.parentDictionaryID = "";
                                }
                                else
                                {
                                    newDataRow.parentDictionaryID = completeData.Value.dict.Value.parentDictionaryID;
                                }
                                newDataRow.detailDesc = indentString + completeData.Value.dict.Value.detailDesc;
                                newDataRow.itemCount = completeData.Value.dat.dataValue;
                                newDataRow.itemPercent = itemValuePercent;
                                newDataRow.stateWideCount = completeData.Value.dict.Value.stateWide;
                                if (completeData.Value.dict.Value.stateWidePercent == "-1")
                                {
                                    newDataRow.stateWidePercent = "";
                                }
                                else
                                {
                                    newDataRow.stateWidePercent = completeData.Value.dict.Value.stateWidePercent + "%";
                                }
                                newSection.dataList.Add(newDataRow);
                            }

                            _ACSDistrictSummaryReportSections.Add(newSection);
                        }
                    }
                }
            }

            NotifyPropertyChanged("ACSDistrictSummaryReportSections");


        }

        public void Print()
        {
            ACSDistrictSummaryPrint acsReport = new ACSDistrictSummaryPrint();
            acsReport.Print(ACSDistrictSummaryReportSections);
        }


        internal bool CanGenerateReport()
        {
            return (isACSDefinitionLoadComplete 
                 //&& !fileOpen.isFileLoading
                 && (districtSelectedIndex >= 1 && districtSelectedIndex <= planDistrictCount)
                 && !isACSDistrictDataSummaryGenerating
                 );
        }

    }
}


